#include "xdialogtransactionstate.h"
#include "xtransport.h"
#include "xtransaction.h"
#include "xrequest.h"
#include "DelayQueue.hh"
#include "xsmallrequest.h"
#include "libxsip.h"
#include "xresponse.h"

#define MAX(a, b) ((a > b) ? a : b)
#define MIN(a, b) ((a < b) ? a : b)

static DelayInterval convert2DelayInterval(int ts)
{
	time_base_seconds sec = ts / 1000;
	time_base_seconds usec = (ts % 1000) * 1000;
	return DelayInterval(sec, usec);
}

XSIPDialogClientTransactionState::XSIPDialogClientTransactionState(void *transaction)
{
	m_transaction = (XSIPTransaction*)transaction;
	m_ts = 250;
	if (m_transaction->getTransport()->getObject("XSIPDgramTransport"))
		m_retran = new RetranEntry(this, convert2DelayInterval(m_ts));
	else
		m_retran = NULL;
	m_ts = MIN(m_ts * 2, 2000);
	m_timeout = new TimeoutEntry(this, DelayInterval(15, 0));
	m_response = NULL;
}

XSIPDialogClientTransactionState::~XSIPDialogClientTransactionState()
{
	if (m_retran)
		delete m_retran;
	delete m_timeout;
}

int XSIPDialogClientTransactionState::touch()
{
	int ret = 0;
	if (m_state == TSX_STATE_SEND_REQUEST)
	{
		XSIPTransport* transport = m_transaction->getTransport();
		XSIPRequest* request = m_transaction->getRequest();
		ret = transport->sendMessage(request, m_transaction);
		if (m_retran)
			XSIPEngine::getCurrentThreadEngine()->addEntry(m_retran);
		XSIPEngine::getCurrentThreadEngine()->addEntry(m_timeout);
	}
	else if (m_state == TSX_STATE_SEND_REQUEST_AGAIN)
	{
		XSIPTransport* transport = m_transaction->getTransport();
		XSIPRequest* request = m_transaction->getRequest();
		ret = transport->sendMessage(request, m_transaction);
		if (m_retran)
			XSIPEngine::getCurrentThreadEngine()->updateEntry(m_retran, convert2DelayInterval(m_ts));
		m_ts = MIN(m_ts * 2, 2000);
	}
	else if (m_state == TSX_STATE_RECV_RESPONSE)
	{
		XSIPDialog *dialog = (XSIPDialog *)m_transaction->getOwner()->getObject("XSIPDialog");
		XSIPDataReceiver* receiver = dialog->getDataReceiver();
		XSIPResponse *response = m_transaction->getResponse();
		if (receiver)
		{
			if (!m_response)
			{
				m_response = response;
				receiver->onResponse(m_transaction, response);
				receiver->onDataRead(m_transaction, response->getContent()->getData(),
					response->getContent()->getSize());
				receiver->onComplete(m_transaction, 0, response);
			}
		}
		else
		{
			ret = dialog->sendAck(m_transaction);
		}
		if (m_response && m_transaction->getAck())
		{
			ret = dialog->sendAck(m_transaction);
		}
		if (m_retran)
			XSIPEngine::getCurrentThreadEngine()->removeEntry(m_retran);
	}
	else if (m_state == TSX_STATE_RECV_ACK)
	{

	}
	else if (m_state == TSX_STATE_SEND_ACK)
	{
		XSIPRequest* request = m_transaction->getAck();
		XSIPTransport* transport = m_transaction->getTransport();
		ret = transport->sendMessage(request, m_transaction);
	}
	else if (m_state == TSX_STATE_TIMEOUT)
	{
		m_transaction->onEvent(m_transaction, XSIP_EVENT_CODE_TIMEOUT);
		if (m_retran)
			XSIPEngine::getCurrentThreadEngine()->removeEntry(m_retran);
	}
	return ret;
}

void XSIPDialogClientTransactionState::complete()
{

}

void XSIPDialogClientTransactionState::timeout()
{
	setState(TSX_STATE_TIMEOUT);
	touch();
}

XSIPDialogServerTransactionState::XSIPDialogServerTransactionState(void *transaction)
{
	m_transaction = (XSIPTransaction*)transaction;
	m_timeout = new TimeoutEntry(this, DelayInterval(15, 0));
	m_ts = 250;
	if (m_transaction->getTransport()->getObject("XSIPDgramTransport"))
		m_retran = new RetranResponse(this, convert2DelayInterval(m_ts));
	else
		m_retran = NULL;
	m_ts = MIN(m_ts * 2, 2000);
}

XSIPDialogServerTransactionState::~XSIPDialogServerTransactionState()
{
	delete m_timeout;
}

int XSIPDialogServerTransactionState::touch()
{
	int ret = 0;
	if (m_state == TSX_STATE_RECV_INVITE)
	{
		XSIPEngine::getCurrentThreadEngine()->onInvite(m_transaction, m_transaction->getRequest());
		XSIPEngine::getCurrentThreadEngine()->addEntry(m_timeout);
	}
	else if (m_state == TSX_STATE_RECV_REINVITE)
	{

	}
	else if (m_state == TSX_STATE_SEND_RESPONSE)
	{
		XSIPTransport* transport = m_transaction->getTransport();
		XSIPResponse* response = m_transaction->getResponse();
		ret = transport->sendMessage(response, m_transaction);
		XSIPEngine::getCurrentThreadEngine()->addEntry(m_retran);
	}
	else if (m_state == TSX_STATE_SEND_RESPONSE_AGAIN)
	{
		XSIPTransport* transport = m_transaction->getTransport();
		XSIPResponse* response = m_transaction->getResponse();
		ret = transport->sendMessage(response, m_transaction);
		if (m_retran)
		XSIPEngine::getCurrentThreadEngine()->updateEntry(m_retran, convert2DelayInterval(m_ts));
		m_ts = MIN(m_ts * 2, 2000);
	}
	else if (m_state == TSX_STATE_RECV_RESPONSE)
	{

	}
	else if (m_state == TSX_STATE_RECV_ACK)
	{
		XSIPDialog *dialog = (XSIPDialog *)m_transaction->getOwner()->getObject("XSIPDialog");
		XSIPEngine::getCurrentThreadEngine()->onAck(dialog, m_transaction);
		complete();
	}
	else if (m_state == TSX_STATE_SEND_ACK)
	{
	}
	else if (m_state == TSX_STATE_TIMEOUT)
	{
		m_transaction->onEvent(m_transaction, XSIP_EVENT_CODE_TIMEOUT);
		if (m_retran)
			XSIPEngine::getCurrentThreadEngine()->removeEntry(m_retran);
	}
	return ret;
}

void XSIPDialogServerTransactionState::complete()
{
	m_transaction->onEvent(m_transaction, XSIP_EVENT_CODE_SUCCESS);
	if (m_retran)
		XSIPEngine::getCurrentThreadEngine()->removeEntry(m_retran);
	XSIPEngine::getCurrentThreadEngine()->removeEntry(m_timeout);
}

void XSIPDialogServerTransactionState::timeout()
{
	setState(TSX_STATE_TIMEOUT);
	touch();
}

RetranResponse::RetranResponse(XSIPTransactionState* state, DelayInterval to)
	: DelayQueueEntry(to), m_state(state)
{

}

RetranResponse::~RetranResponse()
{

}

void RetranResponse::handleTimeout()
{
	m_state->setState(TSX_STATE_SEND_RESPONSE_AGAIN);
	m_state->touch();
}